package com.frank.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.frank.auth.domain.bo.AuthUserBo;
import com.frank.auth.domain.constants.AuthConstant;
import com.frank.auth.domain.convert.AuthUserBoConvert;
import com.frank.auth.domain.service.UserDomainService;
import com.frank.auth.infra.basic.entity.*;
import com.frank.auth.infra.basic.service.*;
import com.frank.common.enums.RedisKeyPrefixEnum;
import com.frank.common.enums.StateEnum;
import com.frank.config.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Frank Zou
 * @version v0.0.1
 * @date 2024/2/9
 * @description
 */
@Slf4j
@Service
public class UserDomainServiceImpl implements UserDomainService {

    private final AuthUserService authUserService;

    private final AuthRoleService authRoleService;

    private final AuthUserRoleService authUserRoleService;

    private final AuthRolePermissionService authRolePermissionService;

    private final AuthPermissionService authPermissionService;

    private final RedisUtil<String, String> redisUtil;


    public UserDomainServiceImpl(
            AuthUserService authUserService,
            AuthRoleService authRoleService,
            AuthUserRoleService authUserRoleService,
            AuthRolePermissionService authRolePermissionService,
            AuthPermissionService authPermissionService,
            RedisUtil<String, String> redisUtil) {
        this.authUserService = authUserService;
        this.authRoleService = authRoleService;
        this.authUserRoleService = authUserRoleService;
        this.authRolePermissionService = authRolePermissionService;
        this.authPermissionService = authPermissionService;
        this.redisUtil = redisUtil;
    }

    public static final String SALT = "jc club";


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBo authUserBo) {
        AuthUser authUser = AuthUserBoConvert.INSTANCE.convertBoToEntity(authUserBo);
        LambdaQueryWrapper<AuthUser> authUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        authUserLambdaQueryWrapper.eq(AuthUser::getUserName, authUser.getUserName());
        int count = authUserService.count(authUserLambdaQueryWrapper);
        if (count > 0) {
            return true;
        }
        if (StringUtils.isNotBlank(authUser.getPassword())) {
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), SALT));
        }
        authUser.setStatus(StateEnum.ENABLED.getCode());
        boolean saveResult = authUserService.save(authUser);
        // 建立一个初步的角色关联
        AuthRole roleResult = saveRoleToRedis(authUser.getUserName());
        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(authUser.getId());
        authUserRole.setRoleId(roleResult.getId());
        authUserRoleService.save(authUserRole);

        String permissionKey = RedisUtil.buildKey(RedisKeyPrefixEnum.PERMISSION_KEY.getKey(), authUser.getUserName());
        savePermissionToRedis(permissionKey, roleResult.getId() + "");
        return saveResult;
    }

    @Override
    public Boolean update(AuthUserBo authUserBo) {
        AuthUser authUser = AuthUserBoConvert.INSTANCE.convertBoToEntity(authUserBo);
        // 如果有任何的更新，都要与缓存进行同步修改
        return authUserService.updateById(authUser);
    }

    @Override
    public Boolean delete(Long userId) {
        return authUserService.removeById(userId);
    }

    @Override
    @Transactional
    public SaTokenInfo doLogin(String captcha) {
        String buildKey = RedisUtil.buildKey("login", "captcha", captcha);
        String openId = redisUtil.get(buildKey);
        log.info("拼接好的 Key: {}, 是否存在: {}, 值: {}", buildKey, redisUtil.exist(buildKey), openId);
        if (openId == null) {
            throw new IllegalArgumentException("验证码错误");
        }
        AuthUserBo authUserBo = new AuthUserBo();
        authUserBo.setUserName(openId);
        this.register(authUserBo);
        StpUtil.login(openId);
        AuthRole authRole;
        String roleKey = RedisUtil.buildKey(RedisKeyPrefixEnum.ROLE_KEY.getKey(), openId);
        if (!redisUtil.exist(roleKey)) {
            authRole = saveRoleToRedis(openId);
        } else {
            LambdaQueryWrapper<AuthRole> roleQueryWrapper = new LambdaQueryWrapper<>();
            roleQueryWrapper.eq(AuthRole::getRoleKey, AuthConstant.NORMAL_USER);
            authRole = authRoleService.getOne(roleQueryWrapper);
        }
        String permissionKey = RedisUtil.buildKey(RedisKeyPrefixEnum.PERMISSION_KEY.getKey(), openId);
        if (!redisUtil.exist(permissionKey)) {
            savePermissionToRedis(permissionKey, String.valueOf(authRole.getId()));
        }


        return StpUtil.getTokenInfo();
    }

    @Override
    public AuthUserBo getUserInfo(String username) {
        LambdaQueryWrapper<AuthUser> authUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        authUserLambdaQueryWrapper.eq(AuthUser::getUserName, username);
        AuthUser one = authUserService.getOne(authUserLambdaQueryWrapper);
        if (one == null) {
            return new AuthUserBo();
        }
        return AuthUserBoConvert.INSTANCE.convertEntityToBo(one);
    }

    /**
     * 保存用户角色信息到 Redis 中
     *
     * @param username 用户名
     * @return 角色对象
     */
    private AuthRole saveRoleToRedis(String username) {
        LambdaQueryWrapper<AuthRole> roleQueryWrapper = new LambdaQueryWrapper<>();
        roleQueryWrapper.eq(AuthRole::getRoleKey, AuthConstant.NORMAL_USER);
        AuthRole roleResult = authRoleService.getOne(roleQueryWrapper);
        String roleKey = RedisUtil.buildKey(RedisKeyPrefixEnum.ROLE_KEY.getKey(), username);
        List<String> roleKeyList = new LinkedList<>();
        roleKeyList.add(roleResult.getRoleKey());
        redisUtil.set(roleKey, JSON.toJSONString(roleKeyList));
        return roleResult;
    }

    /**
     * 保存用户权限信息到 Redis 中
     *
     * @param permissionKey 权限Key
     * @param roleId        角色ID
     */
    private void savePermissionToRedis(String permissionKey, String roleId) {
        LambdaQueryWrapper<AuthRolePermission> rolePermissionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        rolePermissionLambdaQueryWrapper.eq(AuthRolePermission::getRoleId, roleId);
        List<AuthRolePermission> authRolePermissionList = authRolePermissionService.list(rolePermissionLambdaQueryWrapper);
        List<Long> permissionIdList = authRolePermissionList.stream().map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        List<String> permissionKeyList = authPermissionService.listByIds(permissionIdList).stream().map(AuthPermission::getPermissionKey).collect(Collectors.toList());
        redisUtil.set(permissionKey, JSON.toJSONString(permissionKeyList));
    }
}
